package logging

import (
	"errors"
	"fmt"
	"gin_api/core/configure"
	"log"
	"os"
	"runtime"
	"time"
)

const (
	// DefaultLog 默认日志目录
	DefaultLog string = "./storage/logs/app.log"

	// LevelInfo LevelWarn LevelDebug LevelError 日志级别
	LevelInfo  string = "info"
	LevelWarn  string = "warn"
	LevelDebug string = "debug"
	LevelError string = "error"
)

type Logging struct {
	channel string
	level   string
	time    string
	file    string
	line    int
}

func New(channel string) *Logging {
	_, file, line, _ := runtime.Caller(1)
	return &Logging{
		channel: channel,
		file:    file,
		line:    line,
	}
}

func (l *Logging) Info(contents ...interface{}) {
	l.Write(LevelInfo, contents...)
}

func (l *Logging) Debug(contents ...interface{}) {
	l.Write(LevelDebug, contents...)
}

func (l *Logging) Warning(contents ...interface{}) {
	l.Write(LevelWarn, contents...)
}

func (l *Logging) Error(contents ...interface{}) {
	l.Write(LevelError, contents...)
}

// Write 写日志
func (l *Logging) Write(level string, contents ...interface{}) {
	file, _ := l.initLogFile(level)
	defer file.Close()
	content := l.buildContent(contents...)
	file.WriteString(content)
}

// Default Log原生库日志
func Default(level string, content ...interface{}) {
	file, err := openLogFile(DefaultLog)
	if err != nil {
		fmt.Println("文件打开失败")
		return
	}
	// 日志输出文件位置
	log.SetOutput(file)
	// flag选项
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile)
	// 日志前缀
	log.SetPrefix(fmt.Sprintf("[%s]", level))
	log.Printf("%#v", content)

	defer file.Close()
}

// openLogFile 打开日志文件流
func openLogFile(path string) (*os.File, error) {
	return os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
}

// initLogFile 初始化日志文件
func (l *Logging) initLogFile(level string) (*os.File, error) {
	// 获取日志相关配置
	config := fmt.Sprintf("app.logging.%s", l.channel)
	path := configure.GetString(config + ".path")
	daily := configure.GetBool(config + ".daily")
	if level == "" {
		level = configure.GetString(config + ".level")
	}

	if path == "" {
		err := errors.New(fmt.Sprintf("日志初始化失败，没有找到相关配置"))
		return nil, err
	}

	now := time.Now()

	// 按日期归纳
	if daily {
		date := now.Format("20060102")
		filename := path[:len(path)-4]
		fileExt := path[len(path)-4:]
		path = fmt.Sprintf("%s-%s%s", filename, date, fileExt)
	}

	l.level = level
	l.time = now.Format("2006-01-02 15:04:05")

	// 打开日志文件
	return openLogFile(path)
}

func (l *Logging) buildContent(contents ...interface{}) string {
	var str string
	for _, content := range contents {
		switch content.(type) {
		case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool, time.Time:
			str += fmt.Sprintf(" %q", content.(string))
		default:
			str += fmt.Sprintf(" %#v", content)
		}
	}
	// [2022-04-07 10:24:00][level]/gin_api/app.go:120: content
	return fmt.Sprintf("[%s][%s]%s:%d:%s\n", l.time, l.level, l.file, l.line, str)
}
